#ifndef __MSG_H__
#define __MSG_H__

#include <stdint.h>

#define TASK_ERR_OK              0		// successful
#define TASK_ERR_FULL            1	    //event queue was full
#define TASK_NONE                NULL
#define TASK_BROADCAST           NULL
#define TASK_ZOMBIE              ((struct task *)0x1)

#ifndef TASK_CONF_NUMMSGS
#define TASK_CONF_NUMMSGS        32
#endif 

//global events
#define MSG_NONE            0x80
#define MSG_INIT            0x81
#define MSG_POLL            0x82
#define MSG_EXIT            0x83
#define MSG_SERVICE_REMOVED 0x84
#define MSG_CONTINUE        0x85
#define MSG_MSG             0x86
#define MSG_EXITED          0x87
#define MSG_TIMER           0x88
#define MSG_COM             0x89
#define MSG_MAX             0x8a

//
typedef unsigned short lc_t;

#define LC_INIT(s) s = 0;

#define LC_RESUME(s) switch(s) { case 0:

#define LC_SET(s) s = __LINE__; case __LINE__:

#define LC_END(s) }

#ifndef NULL
#define NULL 0
#endif 

struct pt {
  lc_t lc;
};

#define PT_WAITING 0
#define PT_YIELDED 1
#define PT_EXITED  2
#define PT_ENDED   3

/**
 * Initialize a protothread.
 */
#define PT_INIT(pt)   LC_INIT((pt)->lc)

/**
 * Declaration of a protothread.
 */
#define PT_THREAD(name_args) char name_args

/**
 * Declare the start of a protothread inside the C function implementing the protothread.
 */
#define PT_BEGIN(pt) {static struct etimer et;char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)

/**
 * Declare the end of a protothread.
 */
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
                   PT_INIT(pt); return PT_ENDED; }

/**
 * Block and wait until condition is true.
 */
#define PT_WAIT_UNTIL(pt, condition)	        \
  do {						\
    LC_SET((pt)->lc);				\
    if(!(condition)) {				\
      return PT_WAITING;			\
    }						\
  } while(0)

/**
 * Restart the protothread.
 */
#define PT_RESTART(pt)				\
  do {						\
    PT_INIT(pt);				\
    return PT_WAITING;			\
  } while(0)

/**
 * Exit the protothread.
 */
#define PT_EXIT(pt)				\
  do {						\
    PT_INIT(pt);				\
    return PT_EXITED;			\
  } while(0)


/**
 * Yield from the current protothread.
 */
#define PT_YIELD(pt)				\
  do {						\
    PT_YIELD_FLAG = 0;				\
    LC_SET((pt)->lc);				\
    if(PT_YIELD_FLAG == 0) {			\
      return PT_YIELDED;			\
    }						\
  } while(0)

/**
 * Yield from the protothread until a condition occurs.
 */
#define PT_YIELD_UNTIL(pt, cond)		\
  do {						\
    PT_YIELD_FLAG = 0;				\
    LC_SET((pt)->lc);				\
    if((PT_YIELD_FLAG == 0) || !(cond)) {	\
      return PT_YIELDED;			\
    }						\
  } while(0)


//<1> TASK MACRO
/*** Define the beginning of a process. */
#define TASK_BEGIN()             PT_BEGIN(process_pt)

/*** Define the end of a process. */
#define TASK_END()               PT_END(process_pt)

/*** Wait for an event to be posted to the process. */
#define TASK_WAIT_MSG()          PT_YIELD(process_pt)

/* */
#define TASK_WAIT_MSG_TO(x) \
        etimer_set(&et,x); \
			  TASK_WAIT_MSG();

/*** Yield the process for a short while. */
#define TASK_PAUSE()              do {				\
		  msg_post(TASK_CURRENT(), MSG_CONTINUE, NULL);	\
		  TASK_WAIT_MSG();							\
		} while(0)

/*** Wait for an event to be posted to the process, with an extra condition. */
#define TASK_WAIT_MSG_UNTIL(c)    PT_YIELD_UNTIL(process_pt, c)

/*** Get a pointer to the currently running process.*/
#define TASK_CURRENT() task_current
extern struct task *task_current;
//end of task_current

/*** Define task. */
#define TASK_NAME(name) extern struct task name

#define TASK(name, msg, data)			     \
	static PT_THREAD(task_thread_##name(struct pt *process_pt,	\
					       uint32_t msg,	\
					       void* data)); \
	struct task name = { NULL,NULL,NULL, #name,	task_thread_##name }; \
	static PT_THREAD(task_thread_##name(struct pt *process_pt,	\
					       uint32_t msg,	\
					       void* data))


struct task {
  struct task *next;
  struct task *poll_next;
  struct task *cast_next;
  const char *name;
  PT_THREAD((* thread)(struct pt *, uint32_t, void*));
  struct pt pt;
  unsigned char state;
};
//End of TASK MACRO

//task_ function
/*** Start a process.*/
void task_start(struct task *p);

/*** Request a process to be polled.*/
void task_poll(struct task *p);

/***  Cause a process to exit,used in task*/
void task_exit(struct task *p);
//End of task_xx function

//sys_xxxx
/*** Run the system once - call poll handlers and process one event.*/
void sys_init(void);
int sys_run(void);
void sys_start(void);
void sys_start(void);
uint32_t sys_stat(uint32_t cmd, uint32_t iret);

//msg_xxx
uint32_t msg_alloc(void);
int msg_post(struct task *p, uint32_t msg, void* data);
void msg_post_syn(struct task *p, uint32_t msg, void* data);
int msg_post_poll(struct task *p, uint32_t msg, void* data);
int msg_get(struct task *p,uint32_t* msg,void** data);
//end of msg_xx

//broadcast
void msg_broadcast_listen(struct task * p);
void msg_broadcast_undo_listen(struct task * p);

//debug
void UARTInit(uint32_t baudrate);
//printf
typedef unsigned long clock_time_t;

struct timer {
  clock_time_t start;
  clock_time_t interval;
};

struct etimer {
  struct timer timer;
  struct etimer *next;
  struct task *p;
};

void etimer_set(struct etimer *et, clock_time_t interval);


#endif /* __MSG_H__ */
